////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//  Filename:    GoldenGloveGuts.cpp                                          //
//  Developer:   Tommy Riddle                                                 //
//  Create date: 02/17/2006                                                   //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//  Description: This is the class implementation for the slot gut of the     //
//               Australian Slot machine called Golden Glove.                 //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
//        Copyright (c) 2006 - Realtime Gaming.  All rights reserved.         //
////////////////////////////////////////////////////////////////////////////////

#include "GoldenGloveGuts.h"

////////////////////////////////////////////////////////////////////////////
/// GoldenGloveGuts::m_aLineWinSpinResults
///
/// This array is used to quickly get the SpinResult for the number of
/// icons.  It is indexed by wheel icon and then count.  So to get the
/// SpinResult for 5 Catchers, use the following code snippet:
///
///		SpinResult result = m_aLineWinSpinResults[ ICON_CATCHER ][ 5 ];
///
/// In this example result would be set to EVT_FIVE_CATCHER.
////////////////////////////////////////////////////////////////////////////
GoldenGloveGuts::SpinResult GoldenGloveGuts::m_aLineWinSpinResults[][6] = 
{
// Number of icons:			0			1					2					3						4						5
/* ICON_POPCORN */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_POPCORN,		EVT_FOUR_POPCORN,		EVT_FIVE_POPCORN	},
/* ICON_HOT_DOG */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_HOT_DOG,		EVT_FOUR_HOT_DOG,		EVT_FIVE_HOT_DOG	},
/* ICON_BASEBALL */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_BASEBALL,		EVT_FOUR_BASEBALL,		EVT_FIVE_BASEBALL	},
/* ICON_HAT */			{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_HAT,			EVT_FOUR_HAT,			EVT_FIVE_HAT		},
/* ICON_HELMET */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_HELMET,		EVT_FOUR_HELMET,		EVT_FIVE_HELMET		},
/* ICON_TROPHY */		{	EVT_LOSER,	EVT_LOSER,			EVT_TWO_TROPHY,		EVT_THREE_TROPHY,		EVT_FOUR_TROPHY,		EVT_FIVE_TROPHY		},
/* ICON_UMPIRE */		{	EVT_LOSER,	EVT_LOSER,			EVT_TWO_UMPIRE,		EVT_THREE_UMPIRE,		EVT_FOUR_UMPIRE,		EVT_FIVE_UMPIRE		},
/* ICON_FAN */			{	EVT_LOSER,	EVT_LOSER,			EVT_TWO_FAN,		EVT_THREE_FAN,			EVT_FOUR_FAN,			EVT_FIVE_FAN		},
/* ICON_CATCHER */		{	EVT_LOSER,	EVT_ONE_CATCHER,	EVT_TWO_CATCHER,	EVT_THREE_CATCHER,		EVT_FOUR_CATCHER,		EVT_FIVE_CATCHER	},
/* ICON_T */			{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_LOSER,				EVT_LOSER,				EVT_LOSER			},
/* ICON_I */			{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_LOSER,				EVT_LOSER,				EVT_LOSER			},
/* ICON_H */			{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_LOSER,				EVT_LOSER,				EVT_LOSER			},
/* ICON_GLOVE */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_LOSER,				EVT_LOSER,				EVT_LOSER			},
/* ICON_BATTER */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_LOSER,				EVT_LOSER,				EVT_LOSER			}
};

////////////////////////////////////////////////////////////////////////////
/// GoldenGloveGuts::m_aScatterWinSpinResults
///
/// This array is used to quickly get the SpinResult for the number of
/// icons.  It is indexed by icon count only, since Gloves are the only
/// scatter win.  So to get the SpinResult for 5 Gloves, use the
/// following code snippet:
///
///		SpinResult result = m_aScatterWinSpinResults[ 5 ];
///
/// In this example result would be set to EVT_FIVE_GLOVE.
////////////////////////////////////////////////////////////////////////////
GoldenGloveGuts::SpinResult GoldenGloveGuts::m_aScatterWinSpinResults[6] = 
{
	// ICON_COIN			   Number of Icons
	EVT_LOSER,				// 0
	EVT_FEATURE_NEAR_MISS,	// 1
	EVT_TWO_GLOVE,			// 2
	EVT_THREE_GLOVE,		// 3
	EVT_FOUR_GLOVE,			// 4
	EVT_FIVE_GLOVE			// 5
};

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::GoldenGloveGuts()   
///
/// This is the default constructor for the class.
////////////////////////////////////////////////////////////////////////////
GoldenGloveGuts::GoldenGloveGuts()
{
	// If this doesn't compile it means that someone probably added
	// another icon type but did not update the
	// m_aLineWinSpinResults array. 
	C_ASSERT( countof( m_aLineWinSpinResults ) == NUM_VALID_ICONS );

	m_bResetSubGameDataOnNextSpin = false;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::~GoldenGloveGuts()
///
/// Destructor for GoldenGloveGuts. 
////////////////////////////////////////////////////////////////////////////
GoldenGloveGuts::~GoldenGloveGuts()
{
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::getRunnerOnFirstBase()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
bool GoldenGloveGuts::getRunnerOnFirstBase()
{
	// Just return the sub-game data.
    if ( m_subGame->getData( SGDIDX_RUNNER_ON_FIRST_BASE ) )
	{
		return true;
	}

	return false;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::setRunnerOnFirstBase()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::setRunnerOnFirstBase( bool bRunner )
{
	// Set the sub-game data.
	m_subGame->update( SGDIDX_RUNNER_ON_FIRST_BASE, bRunner );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::getRunnerOnSecondBase()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
bool GoldenGloveGuts::getRunnerOnSecondBase()
{
	// Just return the sub-game data.
    if ( m_subGame->getData( SGDIDX_RUNNER_ON_SECOND_BASE ) )
	{
		return true;
	}

	return false;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::setRunnerOnSecondBase()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::setRunnerOnSecondBase( bool bRunner )
{
	// Set the sub-game data.
	m_subGame->update( SGDIDX_RUNNER_ON_SECOND_BASE, bRunner );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::getRunnerOnThirdBase()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
bool GoldenGloveGuts::getRunnerOnThirdBase()
{
	// Just return the sub-game data.
    if ( m_subGame->getData( SGDIDX_RUNNER_ON_THIRD_BASE ) )
	{
		return true;
	}

	return false;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::setRunnerOnThirdBase()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::setRunnerOnThirdBase( bool bRunner )
{
	// Set the sub-game data.
	m_subGame->update( SGDIDX_RUNNER_ON_THIRD_BASE, bRunner );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::getRunsScored()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
int32 GoldenGloveGuts::getRunsScored()
{
	// Just return the sub-game data.
    return m_subGame->getData( SGDIDX_RUNS_SCORED );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::setRunsScored()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::setRunsScored( int32 nRuns )
{
	// Set the sub-game data.
	m_subGame->update( SGDIDX_RUNS_SCORED, nRuns );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::incrementRunsScored()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::incrementRunsScored()
{
	// Just use the other two accessors.
	setRunsScored( getRunsScored() + 1 );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::getLastHit()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
int32 GoldenGloveGuts::getLastHit()
{
	// Just return the sub-game data.
    return m_subGame->getData( SGDIDX_LAST_HIT );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::setLastHit()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::setLastHit( int32 nBases )
{
	// Set the sub-game data.
	m_subGame->update( SGDIDX_LAST_HIT, nBases );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::getIRow()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
int32 GoldenGloveGuts::getIRow()
{
	// Just return the sub-game data.
    return m_subGame->getData( SGDIDX_I_ROW );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::setIRow()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::setIRow( int32 nRow )
{
	// Set the sub-game data.
	m_subGame->update( SGDIDX_I_ROW, nRow );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::getBatterSubstitutionForI()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
bool GoldenGloveGuts::getBatterSubstitutionForI()
{
	// Just return the sub-game data.
	if ( m_subGame->getData( SGDIDX_I_BATTER_SUBSTITUTION ) )
	{
		return true;
	}

	return false;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::setBatterSubstitutionForI()
///
/// Accessor function for sub-game data. 
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::setBatterSubstitutionForI( bool bSubstitute )
{
	// Set the sub-game data.
	m_subGame->update( SGDIDX_I_BATTER_SUBSTITUTION, bSubstitute );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::SpinResult GoldenGloveGuts::getLineWinResultWithPossibleSubstitution( uint8* stops, uint8 testIcon, bool& bSubstitution ) const
///
/// @param   stops			The array of stop positions for the line.
/// @param   testIcon		The icon we are looking for, typically the first icon on the line.
/// @param   bSubstitution	An output parameter that is set if a subsitution is used.
///
/// @return	 SpinResult		A payout from the SpinResult enumeration.
///
/// This helper method is used to calculate the line win payout with a possible substitution.
////////////////////////////////////////////////////////////////////////////
GoldenGloveGuts::SpinResult GoldenGloveGuts::getLineWinResultWithPossibleSubstitution(
	uint8* stops, uint8 testIcon, bool& bSubstitution ) const
{
	// Initialize the out parameter
	bSubstitution = false;

	// Loop through the remaining reels until the streak is over
	for ( int i = 1; i < getReelCount(); i++ )
    {
		// See what this icon is.
		uint8 currentIcon = getIcon( getGameModeId(), i, stops[i] )->iconid;

		// If the current icon is a Batter...
		if ( currentIcon == ICON_BATTER )
		{
			// then use it as a substitution symbol and continue on.
			bSubstitution = true;
			continue;
		}
		// Otherwise if the test icon is a Batter...
		else if ( testIcon == ICON_BATTER )
		{
			// then we still have a substitution.  In this case the line
			// started out with a Batter.
			bSubstitution = true;

			// We have now found our first icon that is not a Batter.  All
			// of the rest of the icons will have to match this one now for the
			// streak to continue, so change our test icon.
			testIcon = currentIcon;
			continue;
		}

		// If the current icon is not the test icon...
        if ( currentIcon != testIcon )
        {
			// then the streak is over so break out of the loop
			break;
        }
    }

	// If we made it all the way through and the testIcon is still a batter...
	if ( testIcon == ICON_BATTER )
	{
		// then this must be a 5 Batter win, so reset the substitution flag.
		bSubstitution = false;
	}
	// Use the array to look up the spin result for i testIcons.
	return lookupLineWinSpinResult( testIcon, i );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::classifyStops()   
///
/// @param   stops      The array of stop positions for the line.
/// @param   bet        The value of the line bet.
/// @param   line       The index of the line.
///
/// This helper method is used to calculate the payout on a line.
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::classifyStops( SpinLine* spinline, uint8* stops, uint8 bet, uint8 line,
	uint8& rtnresult, uint8& multiplier )
{
	// See what the payout is if we use any Batters we find as substitution symbols.
	// Start with the icon on the first reel.
	uint8 testIcon = getIcon( getGameModeId(), 0, stops[0] )->iconid;

	// Declare a local variable to track whether or not we found a substitution.
	bool bSubstitution = false;

	// See what the spin result is if we used any Batters as substitution symbols.
	rtnresult =	getLineWinResultWithPossibleSubstitution( stops, testIcon, bSubstitution );

	// If we did actually have a substitution and a winning spin...
	if ( bSubstitution && rtnresult != EVT_LOSER )
	{
		// then add a note and change the multiplier.
		spinline->addNote( NOTE_SUBSTITUTION );
		multiplier = MULTIPLIER_BATTER_SUBSTITUTION;
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn		GoldenGloveGuts::tryForJackpot()
///
///	This function tries to win the jackpot and adds the scatter if we hit
/// the jackpot.
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::tryForJackpot( SlotSpin* spin )
{
	// If we are in the first paid spin (NOT a bonus spin)...
	if ( getGameModeId() == MODE_NORMAL ) 
	{
		// then try for the Random Progressive Jackpot
		// If we hit the jackpot...
		if ( getRandomProgressiveJackpotResult( spin->getSpinLineCount() ) ||
             m_bForceRandomJackpot == true )
		{
			// then add a jackpot scatter to the spin.
			spin->addScatter( 0,
				getPayout( EVT_RANDOM_PROGRESSIVE_WINNER )->payoutAmount, 1,
				true, EVT_RANDOM_PROGRESSIVE_WINNER, 0 );
		}
    }
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::getScatterWinResult()   
///
/// @param   spin				The spin we are evaluating.
/// @param   et					The direction that we should use when we evaluate the scatter.
/// @param   scatterPositions	An output parameter that contains a bit mask for the icon positions.
/// @param	 bSubstitition		An output parameter that is set to true if a substitution symbol was used.
///
/// @return	 SpinResult			A payout from the SpinResult enumeration.
///
///	This function looks for scatter wins.
////////////////////////////////////////////////////////////////////////////
GoldenGloveGuts::SpinResult GoldenGloveGuts::getScatterWinResult( SlotSpin* spin, EvalType et, int32& scatterPositions, bool& bSubstitution )
{
	// Keep up with how many scatter icons we found.
	uint8 numScatterIcons = 0;

	// Keep up with the direction we are going.
	int nDirection;

	// We need a place to keep up with the starting reel since we can go
	// in either direction.
	int nStartReel;

	// If we are going from left to right...
	if ( et == etLeftToRight )
	{
		// then start at reel 0.
		nStartReel = 0;

		// We will need to increment the reel as we iterate through the loop.
		nDirection = 1;
	}
	// Otherwise if we are looking for a hit...
	else if ( et == etHit )
	{
		// then start at reel 1.
		nStartReel = 1;

		// We will need to increment the reel as we iterate through the loop.
		nDirection = 1;
	}
	// Otherwise if we are looking for the special case near miss...
	else if ( et == etSpecialNearMiss )
	{
		// then start at reel 2.
		nStartReel = 2;

		// We will need to increment the reel as we iterate through the loop.
		nDirection = 1;
	}
	// Otherwise...
	else
	{
		// we must be going from right to left.
		ASSERT( et == etRightToLeft );

		// Start on the last reel.
		nStartReel = getReelCount() - 1;

		// We will need to decrement the reel as we iterate through the loop.
		nDirection = -1;
	}

	// Declare a local array to use when looking for scattered Hits.
	uint8 nHitIconsByReel[5] = 
	{
		ICON_INVALID,
		ICON_H,
		ICON_I,
		ICON_T,
		ICON_INVALID
	};

	// Intitialize the substitution out parameter.
	bSubstitution = false;

	// Keep up with the row that has the I or batter.
	int32 nIRow = -1;

	// Loop through each reel.
  	for( int i = 0; i < getReelCount(); i++ )
	{
		// Figure out what our current reel is for this iteration.
		int reel = nStartReel + ( i * nDirection );

		// The position bit for the current icon in case it needs to be stored in a mask.
		uint8 position = reel;

		// Keep up with whether or not we found a scatter icon on this reel.
		bool bFoundScatterIconOnReel = false;

		// Loop through each row in the wheel house.
		for( int row = 0; row < 3; row++ )
		{
			// Get the current stop.
			uint8 stop = relativeWheelPosition( getGameModeId(), reel,
				spin->getStops()[ reel ], row );

			// Get the icon for the current stop.
			uint8 currentIcon = getIcon( getGameModeId(), reel, stop )->iconid;
			
			// If the icon is a Glove...
			if ( currentIcon == ICON_GLOVE )
			{
				// Set the flag so that we know we found a scatter icon on this reel.
				bFoundScatterIconOnReel = true;
			}
			// Otherwise if the icon is a H, I, or T...
			else if ( currentIcon == nHitIconsByReel[ reel ] )
			{
				// Set the flag so that we know we found a scatter icon on this reel.
				bFoundScatterIconOnReel = true;

				// If this is the I reel...
				if ( reel == 2 )
				{
					// then remember where we found the batter.
					nIRow = row;
				}
			}
			// Otherwise if the icon is a Batter...
			else if ( currentIcon == ICON_BATTER )
			{
				// then set the flag so that we know we found a scatter icon on this reel.
				bFoundScatterIconOnReel = true;

				// In this game Batters substitute for Gloves.
				bSubstitution = true;

				// Remember where we found the batter.
				nIRow = row;
			}

			// If we found a scatter icon...
			if ( bFoundScatterIconOnReel )
			{
				// then increase the scatter icon count
				numScatterIcons++;

				// Set the bit in the position mask for this stop.
				scatterPositions |= 1 << position;

				// Break out now.
				break;
			}

			// Move to the next bit in the position mask.
            position += 5;
		}

		// If we didn't find a scatter icon on the reel...
		if ( !bFoundScatterIconOnReel )
		{
			// then we are done.
			break;
		}
	}

	// If we are looking for a scattered Hit...
	if ( et == etHit )
	{
		// then if we found 3 scatter icons...
		if ( numScatterIcons == 3 )
		{
			// then store the location of the I.
			setIRow( nIRow );

			// Also set a flag if the batter substituted for I.
			setBatterSubstitutionForI( bSubstitution );

			// The result is a hit.
			return EVT_HIT;
		}

		// Otherwise force the I row to -1.
		setIRow( -1 );

		// Also force the substitution flag to false.
		setBatterSubstitutionForI( false );

		// If we found any HIT scatters return near miss
		if ( numScatterIcons > 0 )
		{
			// Omar Segura. #19688. Needed for the anticipation sound for HIT
			// during free games
			return EVT_FEATURE_NEAR_MISS;
		}
		// Otherwise it is a loser.
		else
		{
			return EVT_LOSER;
		}
	}
	// Otherwise if we are looking for the special near miss...
	else if ( et == etSpecialNearMiss )
	{
		// and we found 1 or 2 scatter icons...
		if ( numScatterIcons == 1 || numScatterIcons == 2 )
		{
			// then the result is a near miss.
			return EVT_FEATURE_NEAR_MISS;
		}

		// Otherwise it is a loser.
		return EVT_LOSER;
	}

	// Use the array to look up the spin result.
	return lookupScatterWinSpinResult( numScatterIcons );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::evaluateScatterWin()
///
/// This function determines if the current spin wins a scatter payment and
/// adds the scatter.
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::evaluateScatterWin( SlotSpin* spin, SpinResult srScatterResult, int32 scatterPositions, bool bSubstitution )
{
	// If we got the scatter win
	if ( srScatterResult == EVT_TWO_GLOVE ||
		 srScatterResult == EVT_THREE_GLOVE ||
		 srScatterResult == EVT_FOUR_GLOVE ||
		 srScatterResult == EVT_FIVE_GLOVE )
	{
		// Get the base payout for the scatter.
		int32 nPayout = getPayout( srScatterResult )->payoutAmount;
		
		// Scatters payout based on the total bet, so factor in the number of bet lines.
		nPayout *= spin->getSpinLineCount();

		// Default to no multiplier.
		int32 nMultiplier = 1;

		// If we have a substitution...
		if ( bSubstitution )
		{
			// then factor in the multiplier.
			nMultiplier *= MULTIPLIER_BATTER_SUBSTITUTION;
		}

		// If we are in the Home Run Feature...
		if ( getGameModeId() == MODE_HOME_RUN )
		{
			// then use the Home Run multiplier.
			nMultiplier *= MULTIPLIER_HOME_RUN;
		}
		// Otherwise if we are in the Grand Slam Feature...
		else if ( getGameModeId() == MODE_GRAND_SLAM )
		{
			// then use the Grand Slam multiplier.
			nMultiplier *= MULTIPLIER_GRAND_SLAM;
		}

		// Add the payout to the total win for this spin.
		increaseTotalWin( nPayout * nMultiplier );
    
		// Add a scatter to the spin.
		SlotScatter* pScatter = spin->addScatter( scatterPositions,
			nPayout * getBetPerLine(), nMultiplier, false, srScatterResult, 0 );

		// If we have a substitution...
		if ( bSubstitution )
		{
			// then add the substitution note.
			pScatter->addNote( NOTE_SUBSTITUTION );
		}

		// If we are in the Home Run Feature...
		if ( getGameModeId() == MODE_HOME_RUN )
		{
			// then add the Home Run note.
			pScatter->addNote( NOTE_HOME_RUN );
		}
		// Otherwise if we are in the Grand Slam Feature...
		else if ( getGameModeId() == MODE_GRAND_SLAM )
		{
			// then add the Grand Slam note.
			pScatter->addNote( NOTE_GRAND_SLAM );
		}
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::evaluateHomeRunFeatureTrigger()
///
/// This function determines if the current spin triggers the Home Run
///	feature and adds the scatter.
////////////////////////////////////////////////////////////////////////////
bool GoldenGloveGuts::evaluateHomeRunFeatureTrigger( SlotSpin* spin, SpinResult srScatterResult, EvalType et, int32 scatterPositions )
{
	ASSERT( getGameModeId() == MODE_NORMAL );

	// See if they triggered the Home Run Feature.
	if ( srScatterResult == EVT_THREE_GLOVE ||
		 srScatterResult == EVT_FOUR_GLOVE ||
		 srScatterResult == EVT_FIVE_GLOVE )
	{
		// Change the game mode.
		setGameModeId( MODE_HOME_RUN );

		// Add the free spins.
		incrementFreeSpins( 9 );

		// Initialize the sub game data.
		setRunnerOnFirstBase( false );
		setRunnerOnSecondBase( false );
		setRunnerOnThirdBase( false );
		setRunsScored( 0 );
		setLastHit( 0 );
		setIRow( -1 );
		setBatterSubstitutionForI( false );

		// Add a scatter to the spin for the feature trigger.
		spin->addScatter( scatterPositions, 0, 0, false,
			EVT_HOME_RUN_FEATURE, 9 );

		return true;
	}
	// Otherwise if it was a loser...
	else if ( et == etRightToLeft && 
		      ( srScatterResult == EVT_LOSER ||
			    srScatterResult == EVT_FEATURE_NEAR_MISS ) )
	{
		// then look for a special case feature near miss.
		bool b = false;
		srScatterResult = getScatterWinResult( spin, etSpecialNearMiss, scatterPositions, b );
	}

	// If we had a near miss...
	if ( srScatterResult == EVT_FEATURE_NEAR_MISS )
	{
		// then add a scatter for it.
		spin->addScatter( scatterPositions, 0, 0, false,
			EVT_FEATURE_NEAR_MISS, 0 );
	}

	return false;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::evaluateGrandSlamFeatureTrigger()
///
/// This function determines if the current spin triggers the Grand Slam
///	feature and adds the scatter.
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::evaluateGrandSlamFeatureTrigger( SlotSpin* spin, SpinResult srScatterResult, int32 scatterPositions )
{
	ASSERT( getGameModeId() == MODE_HOME_RUN );

	// See how many runs they scored.
	int32 nSpins = getRunsScored();

	// If they are on the last spin of the Home Run feature and they scored some runs...
	if ( getFreeSpins() == 1 && nSpins > 0 )
	{
		// Change the game mode.
		setGameModeId( MODE_GRAND_SLAM );

		// Add the free spins.
		incrementFreeSpins( nSpins );

		// Initialize the sub game data on the next spin.
		m_bResetSubGameDataOnNextSpin = true;

		// Add a scatter to the spin for the feature trigger.
		spin->addScatter( 0, 0, 0, false,
			EVT_GRAND_SLAM_FEATURE, nSpins );
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::addRunBonusScatter()
///
/// This function adds a scatter for the run bonus.
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::addRunBonusScatter( SlotSpin* spin, int32 scatterPositions )
{
	incrementRunsScored();

	int32 nRunBonus = 0;

	if ( getGameModeId() == MODE_HOME_RUN )
	{
		nRunBonus = BONUS_RUN_SCORED;
	}
	else
	{
		ASSERT( getGameModeId() == MODE_GRAND_SLAM );
		nRunBonus = getRandomValueFromProbabilityTable( PROBABILITY_TABLE_GRAND_SLAM_RUN_BONUS );
	}

	// The run bonus pays out based on the total bet, so factor in the number of bet lines.
	nRunBonus *= spin->getSpinLineCount();

	// Add the payout to the total win for this spin.
	increaseTotalWin( nRunBonus );

	// Add a scatter to the spin for the run bonus.
	spin->addScatter( scatterPositions, nRunBonus * getBetPerLine(), 1, false,
		EVT_RUN, 0 );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::evaluateHit()
///
/// This function determines if the current spin scored any runs and adds
/// the scatters.
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::evaluateHit( SlotSpin* spin, SpinResult srScatterResult, int32 scatterPositions )
{
	ASSERT( getGameModeId() == MODE_HOME_RUN || getGameModeId() == MODE_GRAND_SLAM );

	// Omar Segura. #19688. Anticipation sound for HIT
	// Anticipation sound during feature
	if ( srScatterResult == EVT_FEATURE_NEAR_MISS )
	{
		setLastHit( 0 );

		// Add a scatter to the spin for the near miss.
		spin->addScatter( scatterPositions, 0, 0, false,
		EVT_FEATURE_NEAR_MISS, 0 );
	}
	// See if they got a hit.
	else if ( srScatterResult == EVT_HIT )
	{
		int32 nLastHit = 0;

		if ( getGameModeId() == MODE_HOME_RUN )
		{
			nLastHit = getRandomValueFromProbabilityTable( PROBABILITY_TABLE_HOME_RUN_HITS );
		}
		else
		{
			ASSERT( getGameModeId() == MODE_GRAND_SLAM );
			nLastHit = getRandomValueFromProbabilityTable( PROBABILITY_TABLE_GRAND_SLAM_HITS );
		}

		ASSERT( nLastHit );
		setLastHit( nLastHit );

		if ( getRunnerOnThirdBase() )
		{
			setRunnerOnThirdBase( false );
			addRunBonusScatter( spin, scatterPositions );
		}

		if ( getRunnerOnSecondBase() )
		{
			setRunnerOnSecondBase( false );

			if ( nLastHit == 1 )
			{
				setRunnerOnThirdBase( true );
			}
			else
			{
				addRunBonusScatter( spin, scatterPositions );
			}
		}

		if ( getRunnerOnFirstBase() )
		{
			setRunnerOnFirstBase( false );

			if ( nLastHit == 1 )
			{
				setRunnerOnSecondBase( true );
			}
			else if ( nLastHit == 2 )
			{
				setRunnerOnThirdBase( true );
			}
			else
			{
				addRunBonusScatter( spin, scatterPositions );
			}
		}

		if ( nLastHit == 1 )
		{
			setRunnerOnFirstBase( true );
		}
		else if ( nLastHit == 2 )
		{
			setRunnerOnSecondBase( true );
		}
		else if ( nLastHit == 3 )
		{
			setRunnerOnThirdBase( true );
		}
		else
		{
			addRunBonusScatter( spin, scatterPositions );
		}
	}
	else
	{
		setLastHit( 0 );
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::classifyScatters( SlotSpin* spin )
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This is an override of the framework method.  
/// It determines if the current spin merits free spins or scatter payments.
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::classifyScatters( SlotSpin* spin )
{	
	// Try for the Random Progressive Jackpot
	tryForJackpot( spin );

	// If we are in normal mode...
	if ( getGameModeId() == MODE_NORMAL )
	{
		// Declare a local variable to track the left to right scatter positions.
		int32 nLeftToRightScatterPositions = 0;

		// Declare a local variable to track whether there is a left to right substitution.
		bool bLeftToRightSubstitution = false;

		// See if there is a left to right scatter.
		SpinResult srLeftToRightResult = getScatterWinResult( spin, etLeftToRight, nLeftToRightScatterPositions, bLeftToRightSubstitution );

		// Add the scatter, if any.
		evaluateScatterWin( spin, srLeftToRightResult, nLeftToRightScatterPositions, bLeftToRightSubstitution );

		// Declare a local variable to track the right to left scatter positions.
		int32 nRightToLeftScatterPositions = 0;

		// Declare a local variable to track whether there is a right to left substitution.
		bool bRightToLeftSubstitution = false;

		// See if there is a right to left scatter.
		SpinResult srRightToLeftResult = getScatterWinResult( spin, etRightToLeft, nRightToLeftScatterPositions, bRightToLeftSubstitution );

		// If we did not already get the five gloves going left to right...
		if ( srLeftToRightResult != EVT_FIVE_GLOVE )
		{
			// Add the right to left scatter, if any.
			evaluateScatterWin( spin, srRightToLeftResult, nRightToLeftScatterPositions, bRightToLeftSubstitution );
		}

		// If we did not trigger the feature with the left to right result...
		if ( !evaluateHomeRunFeatureTrigger( spin, srLeftToRightResult, etLeftToRight, nLeftToRightScatterPositions ) )
		{
			// Then see if we triggered it with the right to left result.
			evaluateHomeRunFeatureTrigger( spin, srRightToLeftResult, etRightToLeft, nRightToLeftScatterPositions );
		}
	}
	// Otherwise...
	else
	{
		// Declare a local variable to track the Hit scatter positions.
		int32 nHitScatterPositions = 0;

		// Declare a local variable to track whether there is a Hit substitution.
		bool bHitSubstitution = false;

		// See if there is a Hit scatter.
		SpinResult srHitResult = getScatterWinResult( spin, etHit, nHitScatterPositions, bHitSubstitution );

		// Add the scatter, if any.
		evaluateScatterWin( spin, srHitResult, nHitScatterPositions, bHitSubstitution );

		// See if we scored any runs.
		evaluateHit( spin, srHitResult, nHitScatterPositions );

		// If we are in the Home Run feature...
		if ( getGameModeId() == MODE_HOME_RUN )
		{
			// then see if we triggered the Grand Slam feature.
			evaluateGrandSlamFeatureTrigger( spin, EVT_LOSER, 0 );
		}
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::isValidGuts()   
///
/// @return	 bool8      True if gut is valid.    
///
/// This helper method is used to see if the current gut ID is valid.
////////////////////////////////////////////////////////////////////////////
bool8 GoldenGloveGuts::isValidGuts()
{
	// Make sure that the m_aLineWinSpinResults array has an entry for each reel,
	// and an additional entry in case there are 0 icons on the line.
	// Note:  we can't do this in the constructor because we have to call
	// getReelCount.
	ASSERT( countof( m_aLineWinSpinResults[0] ) == getReelCount( MODE_NORMAL ) + 1 );

	// Make sure that the m_aScatterWinSpinResults array has an entry for each reel,
	// and an additional entry in case there are 0 scatter icons.
	ASSERT( countof( m_aScatterWinSpinResults ) == getReelCount( MODE_NORMAL ) + 1 );

	// Now make sure that all game modes have the same number of reels.
	ASSERT( getReelCount( MODE_NORMAL ) == getReelCount( MODE_HOME_RUN ) );
	ASSERT( getReelCount( MODE_NORMAL ) == getReelCount( MODE_GRAND_SLAM ) );

	// Finally just check to see if the gut is within the right range.
    return ( getGutsId() >= 2700 && getGutsId() < 2800 );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier, uint8& nNoteId )
///
/// @param   nGameModeMultiplier	The multiplier for the game mode.
/// @param   nNoteId				The note ID for the game mode.
///
/// This helper method is used to get the game mode multiplier and note ID.
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier,
	uint8& nNoteId )
{
	// If we are in the Home Run Feature...
    if ( getGameModeId() == MODE_HOME_RUN )
    {
		// then return the Home Run multiplier...
        nGameModeMultiplier = MULTIPLIER_HOME_RUN;

		// and the Home Run note.
        nNoteId = NOTE_HOME_RUN;
    }
	// Otherwise if we are in the Grand Slam Feature...
    else if ( getGameModeId() == MODE_GRAND_SLAM )
    {
		// then return the Grand Slam multiplier...
        nGameModeMultiplier = MULTIPLIER_GRAND_SLAM;

		// and the Grand Slam note.
        nNoteId = NOTE_GRAND_SLAM;
    }
	// Otherwise...
    else
    {
		// just defer to the base class.
        SlotGuts::getGameModeMultiplierAndNoteId( nGameModeMultiplier, nNoteId );
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	Debugging code
//
////////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldenGloveGuts::preSpinClassifyResults( SlotSpin* spin )
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This method is overridden in debug spins mode to alter the reel stops.
////////////////////////////////////////////////////////////////////////////
void GoldenGloveGuts::preSpinClassifyResults( SlotSpin* spin )
{
	SlotGuts::preSpinClassifyResults(spin);

	// If we need to reset the sub game data...
	if ( m_bResetSubGameDataOnNextSpin )
	{
		// then initialize the sub game data to default values.
		setRunnerOnFirstBase( false );
		setRunnerOnSecondBase( false );
		setRunnerOnThirdBase( false );
		setRunsScored( 0 );
		setLastHit( 0 );
		setIRow( -1 );
		setBatterSubstitutionForI( false );

		m_bResetSubGameDataOnNextSpin = false;
	}
}

#ifdef ALLOW_FORCE_BONUS_GAMES
void
GoldenGloveGuts::getBonusGameSpin(uint8* pStops) 
{
	if ( getGameModeId() == MODE_NORMAL )
	{	
		pStops[0] = DebugStops_findStopWithIconID(0, ICON_GLOVE, 1);	
		pStops[1] = DebugStops_findStopWithIconID(1, ICON_GLOVE, 1);
		pStops[2] = DebugStops_findStopWithIconID(2, ICON_GLOVE, 1);
		pStops[3] = DebugStops_findStopWithIconID(3, ICON_GLOVE, 1);
		pStops[4] = DebugStops_findStopWithIconID(4, ICON_GLOVE, 1);
		m_bonusGameNextSpin = true;
	}
	else if ( getGameModeId() == MODE_HOME_RUN 
				&& getRunsScored() < 1)
	{
		pStops[0] = DebugStops_findStopWithIconID(0, ICON_HAT, 1);	
		pStops[1] = DebugStops_findStopWithIconID(1, ICON_H, 1);
		pStops[2] = DebugStops_findStopWithIconID(2, ICON_I, 1);
		pStops[3] = DebugStops_findStopWithIconID(3, ICON_T, 1);
		pStops[4] = DebugStops_findStopWithIconID(4, ICON_BASEBALL, 1);
		m_bonusGameNextSpin = true;
	}

}
#endif

#ifdef ALLOW_FORCE_BONUS_GAMES
void
GoldenGloveGuts::getBonusGameSpin(uint8* pStops) 
{
	if ( getGameModeId() == MODE_NORMAL )
	{	
		pStops[0] = DebugStops_findStopWithIconID(0, ICON_GLOVE, 1);	
		pStops[1] = DebugStops_findStopWithIconID(1, ICON_GLOVE, 1);
		pStops[2] = DebugStops_findStopWithIconID(2, ICON_GLOVE, 1);
		pStops[3] = DebugStops_findStopWithIconID(3, ICON_GLOVE, 1);
		pStops[4] = DebugStops_findStopWithIconID(4, ICON_GLOVE, 1);
		m_bonusGameNextSpin = true;
	}
	else if ( getGameModeId() == MODE_HOME_RUN 
				&& getRunsScored() < 1)
	{
		pStops[0] = DebugStops_findStopWithIconID(0, ICON_HAT, 1);	
		pStops[1] = DebugStops_findStopWithIconID(1, ICON_H, 1);
		pStops[2] = DebugStops_findStopWithIconID(2, ICON_I, 1);
		pStops[3] = DebugStops_findStopWithIconID(3, ICON_T, 1);
		pStops[4] = DebugStops_findStopWithIconID(4, ICON_BASEBALL, 1);
		m_bonusGameNextSpin = true;
	}

}
#endif